<!-- spu表单 -->
<template>
    <el-form :model="spuForm" :rules="spuRules" ref="ruleForm" label-width="120px">
        <el-form-item label="SPU名称" prop="spuName">
            <el-input placeholder="请输入SPU名称" v-model="spuForm.spuName"></el-input>
        </el-form-item>

        <el-form-item label="品牌" prop="tmId">
            <el-select placeholder="请选择品牌" v-model="spuForm.tmId">
                <el-option :label="tm.tmName" :value="tm.id" v-for="(tm,index) in trademarkList" :key="tm.id">
                </el-option>
            </el-select>
        </el-form-item>

        <el-form-item label="SPU描述" prop="description">
            <el-input type="textarea" rows="4" placeholder="请输入SPU描述" v-model="spuForm.description"></el-input>
        </el-form-item>

        <el-form-item label="SPU图片">
            <el-upload action="/dev-api/admin/product/admin/product/fileUpload" list-type="picture-card"
                :file-list="spuImageList" :on-preview="handlePictureCardPreview" :on-remove="handleRemove"
                :on-success="handleSuccess">
                <i class="el-icon-plus"></i>
            </el-upload>
            <el-dialog :visible.sync="dialogVisible">
                <img width="100%" :src="dialogImageUrl" alt="">
            </el-dialog>
        </el-form-item>
        <el-form-item label="销售属性">
            <el-select :placeholder="`还有${countSelectSaleAttr.length}个未选择`" v-model="attrIdAndName">
                <el-option :label="saleAttr.name" :value="`${saleAttr.id}:${saleAttr.name}`"
                    v-for="(saleAttr,index) in countSelectSaleAttr" :key="saleAttr.id"></el-option>
            </el-select>
            <el-button type="primary" icon="el-icon-plus" style="margin-left: 20px;" :disabled="!attrIdAndName"
                @click="addSaleAttr">添加销售属性
            </el-button>
            <el-table :data="spuForm.spuSaleAttrList" stripe border empty-text="暂无数据" style="margin-top: 20px;">
                <el-table-column type="index" label="序号" width="120" align="center"></el-table-column>
                <el-table-column prop="saleAttrName" label="属性名" width="150" align="center"></el-table-column>
                <el-table-column prop="prop" label="属性值名称列表" width="width">
                    <template slot-scope="{row,$index}">
                        <el-tag v-for="(tag,index) in row.spuSaleAttrValueList" :key="tag.id" closable
                            :disable-transitions="false" @close="handleClose(row,index)">
                            {{tag.saleAttrValueName}}
                        </el-tag>
                        <el-input class="input-new-tag" v-if="row.inputVisible" v-model="row.inputValue"
                            ref="saveTagInput" size="small" @blur="handleInputConfirm(row)">
                        </el-input>
                        <el-button v-else class="button-new-tag" icon="el-icon-plus" size="small"
                            @click="addSaleAttrValue(row)">添加
                        </el-button>
                    </template>
                </el-table-column>
                <el-table-column prop="prop" label="操作" width="300" align="center">
                    <template slot-scope="{row,$index}">
                        <!-- 这里的点击确认按钮触发的回调：官网中显示的是 confirm 由于版本问题 这边需要使用 onConfirm -->
                        <el-popconfirm :title='`确定删除${row.saleAttrName}吗？`' @onConfirm="deleteSaleAttr($index)">
                            <el-button slot="reference" type="danger" icon="el-icon-delete" size="small">
                                删除
                            </el-button>
                        </el-popconfirm>
                    </template>
                </el-table-column>
            </el-table>
        </el-form-item>

        <el-form-item>
            <el-button type="primary" style="margin:10px 10px 0px 0px" @click="addOrUpdataSpuInfo">保存</el-button>
            <el-button @click="cancelForm">取消</el-button>
        </el-form-item>
    </el-form>
</template>
<script>
    export default {
        name: "SpuForm",

        computed: {
            // 计算出未选择的平台销售属性  ||  全部属性(一共三个) - 商品有的属性
            countSelectSaleAttr() {
                // 通过filter和every遍历两个数组，返回出属性值不相等的元素，并组成新的数组
                const result = this.baseSaleAttrList.filter(item => {
                    return this.spuForm.spuSaleAttrList.every(item1 => {
                        return item.name !== item1.saleAttrName
                    })
                })
                return result;
            }
        },
        data() {
            // 自定义表单验证规则
            var validateTm = (rule, value, callback) => {
                if (value === '') {
                    callback(new Error('请选择品牌'));
                } else {
                    callback();
                }
            };
            return {
                dialogImageUrl: '', // 图片墙图片弹框的图片路径
                dialogVisible: false, // 图片墙预览弹框的显示与隐藏
                trademarkList: [], // 品牌属性列表 ->下拉框
                baseSaleAttrList: [], // 销售属性列表 ->下拉框
                spuImageList: [],  // // spu图片墙列表 -> 服务器返回的数据用于展示
                spuForm: {
                    category3Id: '', // 三级列表id
                    spuName: "", // spu名称
                    description: "", // spu描述
                    tmId: '', // 品牌id
                    spuImageList: [], // spu图片墙列表 -> 收集数据发送给服务器
                    spuSaleAttrList: [], // 销售属性列表 ->表格
                },
                attrIdAndName: '', // 收集未选择的平台属性id
                spuRules: { // spu表单的验证规则 | 验证规则的变量名必须和被验证的表单中对应元素一样否则无法进行验证
                    spuName: [ // spu名称
                        { required: true, message: '请输入SPU名称', trigger: 'change' },
                    ],
                    tmId: [ // 品牌(自定义)
                        { validator: validateTm, required: true, trigger: 'change' }
                    ],
                    description: [ // spu描述
                        { required: true, message: '请输入SPU描述', trigger: 'change' },
                    ]
                }
            }
        },
        methods: {
            // 移除图片墙中的图片
            handleRemove(file, fileList) {
                this.spuImageList = fileList // 收集删除后的剩余的图片列表
            },
            // 上传图片墙中的图片成功时
            handleSuccess(response, file, fileList) {
                this.spuImageList = fileList // 收集上传成功后的图片列表
            },
            // 放大图片墙中的图片
            handlePictureCardPreview(file) {
                this.dialogImageUrl = file.url;
                this.dialogVisible = true;
            },
            // 取消表单 | flag：通知父组件当前所做操作室添加spu还是修改spu，这边不用为空就好
            cancelForm() {
                this.$emit('spuChangeScene', { scene: 0, flag: '' }) // 通过自定义事件将父组件的页面下半部状态改为默认状态|0
                // 清除数据
                // this._data : 当前组件的所有响应式数据
                // this.$options.data : 当前组件的data函数执行返回的数据都为空
                Object.assign(this._data, this.$options.data())
            },
            // 初始化spu数据
            initSpuData(row) {
                this.getSpuInfo(row.id)
                this.getTrademarkList()
                this.getSpuImageList(row.id)
                this.getSaleAttrLsit()
            },
            // 获取spu基本信息
            async getSpuInfo(spuId) {
                const result = await this.$api.spu.reqGetSpuInfo(spuId)
                if (result.code == 200) {
                    this.spuForm = result.data
                }
            },
            // 获取品牌列表数据
            async getTrademarkList(category3Id) {
                // 添加spu时接受父组件传过来的category3Id并保存
                this.spuForm.category3Id = category3Id

                const result = await this.$api.spu.reqGetTrademarkList()
                if (result.code == 200) {
                    this.trademarkList = result.data
                }
            },
            // 获取spu图片墙数据
            async getSpuImageList(spuId) {
                const result = await this.$api.spu.reqGetSpuImageList(spuId)
                if (result.code == 200) {
                    const newSpuImageList = result.data // 获取服务器数据并赋值给变量
                    // element ui 的上传图片墙用到的file-list属性，需要用到name和url作为变量名所以这边需要添加上
                    newSpuImageList.forEach(item => { // 遍历数组并新增两个数据
                        item.name = item.imgName // 将源数据的imgName赋值给name
                        item.url = item.imgUrl // 将源数据的imgUrl赋值给url
                    });
                    this.spuImageList = newSpuImageList // 将整理好的数组保存到本地数据中
                }
            },
            // 获取spu销售属性列表数据 ->下拉框
            async getSaleAttrLsit() {
                const result = await this.$api.spu.reqGetSaleAttrList()
                if (result.code == 200) {
                    this.baseSaleAttrList = result.data
                }
            },
            // 添加销售属性
            addSaleAttr() {
                // 拆分收集的销售属性id和name 并结构获取到
                const [baseSaleAttrId, saleAttrName] = this.attrIdAndName.split(':')
                // 向数组中添加数据
                this.spuForm.spuSaleAttrList.push({
                    baseSaleAttrId,
                    saleAttrName,
                    spuSaleAttrValueList: []
                })
                this.attrIdAndName = '' // 将收集销售属性id和name清空防止多次收集同一属性
            },
            // 删除销售属性
            deleteSaleAttr(index) {
                this.spuForm.spuSaleAttrList.splice(index, 1)
            },
            // 点击添加属性值按钮时
            addSaleAttrValue(row) {
                this.$set(row, 'inputVisible', true) // 添加响应式元素 并显示input
                this.$set(row, 'inputValue', '') // 收集input数据
                this.$nextTick(() => { // 聚焦input
                    this.$refs.saveTagInput.focus();
                });
            },
            // 隐藏input, 失焦或者按下回车键触发
            handleInputConfirm(row) {
                const inputValue = row.inputValue  // 获取当前input框收集的数据
                const addSpuSaleAttrValue = { // 将要push到数组中的数据
                    baseSaleAttrId: row.baseSaleAttrId,
                    saleAttrName: row.saleAttrName,
                    saleAttrValueName: inputValue
                }

                // 判断输入的值是否符合要求
                if (inputValue.trim() == '') { // 当输入的值是空格时
                    this.$message({
                        message: '请输入正确格式的属性值',
                        type: 'warning'
                    });
                    return; // 直接返回不再执行函数，方便用户再次输入
                }
                // 判断新增的销售属性值是否重复
                const isRepeat = row.spuSaleAttrValueList.some(item => {
                    return item.saleAttrValueName == addSpuSaleAttrValue.saleAttrValueName
                })
                if (isRepeat) { // 当输入重复时
                    this.$message({
                        message: '不能输入重复的属性名，请重新输入',
                        type: 'warning'
                    });
                    return; // 直接返回不再执行函数，方便用户再次输入
                }

                row.spuSaleAttrValueList.push(addSpuSaleAttrValue);
                row.inputVisible = false // 隐藏input
                row.inputValue = '' // 清空本地储存的inputValue
            },
            // 删除属性值
            handleClose(row, index) {
                // index为当前点击属性值的下标
                row.spuSaleAttrValueList.splice(index, 1); // 删除属性值列表中的当前点击那一项
            },

            // 点击保存 | 整理并收集表单数据提交给服务器
            addOrUpdataSpuInfo() {
                this.$refs.ruleForm.validate(async (success) => {
                    if (success) { // 如果表单验证通过，继续业务逻辑
                        // 整理spu数据
                        // 整理图片墙数据 | 后台需要每个图片存在 imgName 和 imgUrl 属性，而我们这边本地添加的图片不存在这两个属性
                        this.spuImageList.forEach((item) => { // 遍历图片墙给其中每个元素添加imgName和imgUrl属性并覆盖原数据
                            item.imgName = item.name
                            item.imgUrl = (item.response && item.response.data) || item.url  // item.response.data为该图片在后台的地址
                        })
                        this.spuForm.spuImageList = this.spuImageList
                        const spuInfo = this.spuForm
                        const result = await this.$api.spu.reqSaveOrUpdateSpuInfo(spuInfo)
                        if (result.code == 200) {
                            this.$message({
                                message: '保存成功！',
                                type: 'success'
                            });
                            this.$emit('changeScene', { scene: 0, flag: this.spuForm.id ? '修改' : '添加' }) // 通过自定义事件将父组件的页面下半部状态改为默认状态|0
                        }
                        // 清除数据
                        // this._data : 当前组件的所有响应式数据
                        // this.$options.data : 当前组件的data函数执行返回的数据都为空
                        Object.assign(this._data, this.$options.data())
                    } else {
                        return false
                    }
                })
            }
        }
    }
</script>
<style>
    .el-tag+.el-tag {
        margin-left: 10px;
    }

    .button-new-tag {
        margin-left: 10px;
        height: 32px;
        line-height: 30px;
        padding-top: 0;
        padding-bottom: 0;
    }

    .input-new-tag {
        width: 90px;
        margin-left: 10px;
        vertical-align: bottom;
    }
</style>